/*
 * SearchWithArrays.cpp
 *
 *  Created on: Jun 1, 2009
 *      Author: ruslan
 */

#include "SearchWithArrays.h"

SearchWithArrays::SearchWithArrays(int weeks, int groupsInWeek, int playersInGroup, long maxIteration=-1)
	:Search(weeks, groupsInWeek, playersInGroup, maxIteration) {
	mtrxFreeCouples = NULL;
	arrFreePlayersInWeek = NULL;
}

SearchWithArrays::~SearchWithArrays() {
	if (arrFreePlayersInWeek != NULL)
		delete [] arrFreePlayersInWeek;

	if (mtrxFreeCouples != NULL) {
		for (int i=0; i<playersCnt; i++)
			delete [] mtrxFreeCouples[i];
		delete [] mtrxFreeCouples;
	}

}

void SearchWithArrays::init() {
	mtrx3Schedule = new int** [WEEKS];
	for (int i=0; i<WEEKS; i++) {
		mtrx3Schedule[i] = new int* [GROUPS_IN_WEEK];
		for (int j=0; j<GROUPS_IN_WEEK; j++) {
			mtrx3Schedule[i][j] = new int [PLAYERS_IN_GROUP];
			for (int k=0; k<PLAYERS_IN_GROUP; k++) {
				mtrx3Schedule[i][j][k] = -1;
			}
		}
	}

	mtrxFreeCouples = new int* [playersCnt];
	arrFreePlayersInWeek = new bool[playersCnt];
	for (int i=0; i<playersCnt; i++) {
		mtrxFreeCouples[i] = new int [playersCnt];
		for (int j=0; j<playersCnt; j++) {
			if (i==j)
				mtrxFreeCouples[i][j] = -2; // isn't allowed
			else
				mtrxFreeCouples[i][j] = -1; // allowed
		}
	}
}

int SearchWithArrays::ScheduleIt() {
	status = 0; // solution is found
	currIteration = 0;
	int i=0, j=0, k=0;
	int maxInd = -1;
	bool hotExit = false;
	while (i<WEEKS && !hotExit) {
		fillSetOfFreePlayersInWeek(true);
		j=0;
		while (j<GROUPS_IN_WEEK && !hotExit) {
			k=0;
			while (k<PLAYERS_IN_GROUP) {
				currIteration++;
				if ( (MAX_ITERATION>-1 && currIteration > MAX_ITERATION) || hotScheduleStop) {
					int tmpInd = i*GROUPS_IN_WEEK*PLAYERS_IN_GROUP+j*PLAYERS_IN_GROUP+k - 1;
					if (maxInd < tmpInd) {
						snapshot();
						maxInd = tmpInd;
					}
					status = -2; // solution was not found. Algorithm is stopped
					hotExit = true;
					currIteration--; // for good answer
					break;
				}
				bool nextPlayerRes = getNextPlayerInGroup(i, j, k);
				if (nextPlayerRes)
					k++;
				else {
					int tmpInd = i*GROUPS_IN_WEEK*PLAYERS_IN_GROUP+j*PLAYERS_IN_GROUP+k;
					if (maxInd < tmpInd) {
						snapshot();
						maxInd = tmpInd;
					}
					if (k>0)
						k--;
					else {
						k = PLAYERS_IN_GROUP - 1;
						if (j>0)
							j--;
						else {
							j = GROUPS_IN_WEEK - 1;
							i--;
							if (i>=0)
								fillSetOfFreePlayersInWeek(false);
							else
							{
								status = -1; // there is not solution for this combination
								hotExit = true;
								break;
							}
						}
					}
				}
			}
			j++;
		}
		i++;
	}

	if (status == 0)
		snapshot();

	return status;
}

void SearchWithArrays::fillSetOfFreePlayersInWeek(bool value){
	for (int i=0; i<playersCnt; i++) {
		arrFreePlayersInWeek[i] = value;
	}
}

bool SearchWithArrays::getNextPlayerInGroup(int i, int j, int k) {
	bool result = false;
	int tmpPlayer = mtrx3Schedule[i][j][k];
	if (k == 0) {
		if (tmpPlayer > -1) {
			arrFreePlayersInWeek[tmpPlayer] = true;
			mtrx3Schedule[i][j][k] = -1;
		}
		tmpPlayer++;
		int maxTmpPlayer = PLAYERS_IN_GROUP*j;
		//int maxTmpPlayer = playersCnt-1;
		while (tmpPlayer <= maxTmpPlayer && arrFreePlayersInWeek[tmpPlayer] == false)
			tmpPlayer++;
		if (tmpPlayer <= maxTmpPlayer) {
			arrFreePlayersInWeek[tmpPlayer] = false;
			mtrx3Schedule[i][j][k] = tmpPlayer;
			result = true;
		}


	}//if (k == 0)
	else {
		// delete all information about previous selected player for this cell
		if (tmpPlayer > -1) {
			arrFreePlayersInWeek[tmpPlayer] = true;
			for (int k1=k-1; k1>-1; k1--) {
				// set player allowable to play in pairs
				mtrxFreeCouples[tmpPlayer][mtrx3Schedule[i][j][k1]] = -1;
				mtrxFreeCouples[mtrx3Schedule[i][j][k1]][tmpPlayer] = -1;
			}
			mtrx3Schedule[i][j][k] = -1;
		}
		int prevPlayer = mtrx3Schedule[i][j][k-1];
		tmpPlayer = (prevPlayer>=tmpPlayer)? prevPlayer+1: tmpPlayer+1;
		bool playerFound = false;
		while (!playerFound && tmpPlayer<playersCnt) {
			while (tmpPlayer<playersCnt && (!arrFreePlayersInWeek[tmpPlayer] || mtrxFreeCouples[prevPlayer][tmpPlayer]!=-1))
				tmpPlayer++;
			if (tmpPlayer<playersCnt) {
				playerFound = true;
				for (int k1=0; k1<k-1; k1++) {
					playerFound = playerFound && (mtrxFreeCouples[mtrx3Schedule[i][j][k1]][tmpPlayer] == -1);
				}
				if (!playerFound)
					tmpPlayer++;
			}
		}

		if (playerFound) {
			arrFreePlayersInWeek[tmpPlayer] = false;
			for (int k1=0; k1<k; k1++) {
				mtrxFreeCouples[tmpPlayer][mtrx3Schedule[i][j][k1]] = i;
				mtrxFreeCouples[mtrx3Schedule[i][j][k1]][tmpPlayer] = i;
			}
			mtrx3Schedule[i][j][k] = tmpPlayer;
			result = true;
		}
	}

	return result;
}

void SearchWithArrays::snapshot() {
	if (mtrx3BestSchedule != NULL)
			Lib::deleteMatrix3(mtrx3BestSchedule, WEEKS, GROUPS_IN_WEEK);
	mtrx3BestSchedule = Lib::makeCopyOfMtrx3(mtrx3Schedule, WEEKS, GROUPS_IN_WEEK, PLAYERS_IN_GROUP);
	bestIteration = currIteration;
}

